package com.bjy.qa.agent.tools.juel;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.TextCodec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class Auth {
    private static final Logger logger = LoggerFactory.getLogger(Auth.class);

    /**
     * basic 认证
     * @param user 用户名
     * @param passwod 密码
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String basic(String user, String passwod) {
        final Base64.Encoder encoder = Base64.getEncoder();
        final String text = user + ":" + passwod;
        final byte[] textByte;
        try {
            textByte = text.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            logger.error("basic auth error: {}", e.getMessage());
            throw new RuntimeException(e);
        }
        String encodedText = "Basic " + encoder.encodeToString(textByte);;
        return encodedText;
    }

    /**
     * BJY 签名，没有签名业务，只是将将key变量替换成value
     * @param arg
     * @return
     */
    public static String signBJY(String arg) {
        return "${auth:sign_bjy(" + arg + ")}";
    }

    /**
     * BJY BRTC 签名
     * @param appID appKey 也是 appID
     * @param appSecret appSecret
     * @param userId 用户ID
     * @param roomId 房间号
     * @param curr_time 当前时间戳
     * @param expire 有效期
     * @return
     */
    public static String signBJY_BRTC(String appID, String appSecret, String userId, String roomId, long curr_time, long expire) {
        BRTCSign calSig = new BRTCSign();
        return calSig.genSign(appID, appSecret, userId, roomId, curr_time, expire);
    }

    /**
     * BJY BRTC 签名
     * @param appID appKey 也是 appID
     * @param appSecret appSecret
     * @param userId 用户ID
     * @param roomId 房间号
     * @return
     */
    public static String signBJY_BRTC(String appID, String appSecret, String userId, String roomId) {
        return signBJY_BRTC(appID, appSecret, userId, roomId, System.currentTimeMillis(), 3600 * 1000);
    }

    /**
     * @param params
     * @return
     */
    public static String sign_JWT(String... params) {
        //判断参数个数，如果不是3的倍数余1，抛异常
        if ((params.length - 1) % 3 != 0) {
            logger.error("Sign JWT error: 参数传递个数有误，key/type/vlue 和 secret");
            throw new RuntimeException("参数传递有误，key/type/vlue 和 secret");
        }
        String secret = params[params.length - 1];
        Map<String, Object> map = convertToJson(params);
        return getJWTSign(secret, map);
    }

    /**
     * 获取JWT签名
     * @param tokenSecret
     * @param claimMap
     * @return
     */
    public static String getJWTSign(String tokenSecret, Map<String, Object> claimMap) {
        //如果没有传过期时间，生成默认值，如果过期时间传的是10位 扩至13位
        Date expDate = null;
        if (claimMap.containsKey("exp")) {
            String expvValue = claimMap.get("exp").toString();
            if (expvValue.length() == 10){
                expDate = new Date(Long.parseLong(claimMap.get("exp").toString()) * 1000L);
            } else if (expvValue.length() == 13){
                expDate = new Date(Long.parseLong(claimMap.get("exp").toString()));
            } else {
                expDate = new Date(System.currentTimeMillis() + 3 * 24 * 60 * 60 * 1000);
            }
        } else {
            expDate = new Date(System.currentTimeMillis() + 3 * 24 * 60 * 60 * 1000);
        }

        //签名
        String token = Jwts.builder()
                .setClaims(claimMap) //写入数据
                .signWith(SignatureAlgorithm.HS256, TextCodec.BASE64.encode(tokenSecret)) //指定加密算法
                .setExpiration(expDate) //失效时间
                .compact();
        return token;
    }

    /**
     * @param params
     * @return
     */
    public static Map<String, Object> convertToJson(String... params) {
        Map<String, Object> result = new HashMap<>();
        for (int i = 0; i < params.length-3; i += 3) {
            String key = params[i];
            String type = params[i + 1];
            String value = params[i + 2];
            // 根据类型转换值
            Object valObj = null;
            if ("int".equalsIgnoreCase(type) || "integer".equalsIgnoreCase(type)) {
                valObj = Integer.valueOf(value);
            } else if ("float".equalsIgnoreCase(type)) {
                valObj = Float.valueOf(value);
            } else if ("long".equalsIgnoreCase(type)) {
                valObj = Long.valueOf(value);
            } else if ("string".equalsIgnoreCase(type)) {
                valObj = value;
            } else {
                throw new RuntimeException("参数类型传递有误，仅支持：Integer/Float/Long/String 类型");
            }

            // 构建键值对
            String[] keys = key.split("\\.");
            Map<String, Object> tempMap = result;
            for (int j = 0; j < keys.length - 1; j++) {
                // 递归构建Map
                String mapKey = keys[j];
                Object mapValue = tempMap.get(mapKey);
                if (mapValue == null) {
                    mapValue = new HashMap<String, Object>();
                    tempMap.put(mapKey, mapValue);
                }
                tempMap = (Map<String, Object>) mapValue;
            }
            // 放入值
            tempMap.put(keys[keys.length - 1], valObj);
        }
        return result;
    }
}
